package com.skivingcloud.admin.sys.controller;

import com.skivingcloud.admin.sys.service.GenerateIDUtil;
import com.skivingcloud.common.utils.ReturnT;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.concurrent.*;

/**
 * @author hushouquan
 * @since 2024/1/11
 */
@Tag(name = "CommonExampleController", description = "控制层示例")
@RestController
@RequestMapping("/commonExample")
public class CommonExampleController{
    
    private static final Logger log = LoggerFactory.getLogger(CommonExampleController.class);
    
    @Resource
    private GenerateIDUtil redisGenerateIDUtil;
    
    /**
     * 测试分布式全局id获取，单个
     * @return 结果
     */
    @GetMapping("/testRedisGenerateIDUtilSingle")
    @Operation(summary="测试分布式全局id获取(单个)")
    public ReturnT<String> testRedisGenerateIDUtilSingle() {
        try{
            // 定义一个线程池 设置核心线程数和最大线程数都为100，队列根据需要设置
            ThreadPoolExecutor executor = new ThreadPoolExecutor(100, 100, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<>(10000));
            CountDownLatch countDownLatch = new CountDownLatch(10000);
            
            long beginTime = System.currentTimeMillis();
            // 获取10000个全局唯一ID 看看是否有重复
            CopyOnWriteArraySet<String> ids = new CopyOnWriteArraySet<>();
            for (int i = 0; i < 10000; i++) {
                executor.execute(() -> {
                    // 获取全局唯一ID
                    long beginTime02 = System.currentTimeMillis();
                    String orderNo = redisGenerateIDUtil.generateId("NO", "1", 10);
                    log.info("获取单个ID耗时 time={}", System.currentTimeMillis() - beginTime02);
                    if (ids.contains(orderNo)) {
                        log.info("重复ID={}", orderNo);
                    } else {
                        ids.add(orderNo);
                    }
                    countDownLatch.countDown();
                });
            }
            countDownLatch.await();
            // 打印获取到的全局唯一ID集合数量
            log.info("获取到全局唯一ID count={}", ids.size());
            log.info("耗时毫秒 time={}", System.currentTimeMillis() - beginTime);
            return ReturnT.ok();
        }catch(Exception e){
            log.error(e.getMessage(), e);
            return ReturnT.ok();
        }
    }
    
    /**
     * 测试分布式全局id获取，批量
     * @return 结果
     */
    @GetMapping("/testRedisGenerateIDUtilBatch")
   @Operation(summary="测试分布式全局id获取(批量)")
    public ReturnT<String> testRedisGenerateIDUtilBatch() {
        try{
            // 定义一个线程池 设置核心线程数和最大线程数都为100，队列根据需要设置
            ThreadPoolExecutor executor = new ThreadPoolExecutor(100, 100, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<>(10000));
            CountDownLatch countDownLatch = new CountDownLatch(10000);
            
            long beginTime = System.currentTimeMillis();
            // 获取10000个全局唯一ID 看看是否有重复
            CopyOnWriteArraySet<List<String>> ids = new CopyOnWriteArraySet<>();
            for (int i = 0; i < 10000; i++) {
                executor.execute(() -> {
                    // 获取全局唯一ID
                    long beginTime02 = System.currentTimeMillis();
                    List<String> orderNo = redisGenerateIDUtil.generateIdBatch("NO", "1", 100, 10);
                    log.info("获取批量(100)耗时 time={}", System.currentTimeMillis() - beginTime02);
                    if (ids.contains(orderNo)) {
                        log.info("重复ID={}", orderNo);
                    } else {
                        ids.add(orderNo);
                    }
                    countDownLatch.countDown();
                });
            }
            countDownLatch.await();
            // 打印获取到的全局唯一ID集合数量
            log.info("获取到全局唯一ID count={}", ids.size());
            log.info("耗时毫秒 time={}", System.currentTimeMillis() - beginTime);
            return ReturnT.ok();
        }catch(Exception e){
            log.error(e.getMessage(), e);
            return ReturnT.ok();
        }
    }
}
